﻿#region Copyright (c) 2000-2008 Developer Express Inc.
/*
{*******************************************************************}
{                                                                   }
{       Developer Express .NET Component Library                    }
{       AgDataGrid                                 }
{                                                                   }
{       Copyright (c) 2000-2008 Developer Express Inc.              }
{       ALL RIGHTS RESERVED                                         }
{                                                                   }
{   The entire contents of this file is protected by U.S. and       }
{   International Copyright Laws. Unauthorized reproduction,        }
{   reverse-engineering, and distribution of all or any portion of  }
{   the code contained in this file is strictly prohibited and may  }
{   result in severe civil and criminal penalties and will be       }
{   prosecuted to the maximum extent possible under the law.        }
{                                                                   }
{   RESTRICTIONS                                                    }
{                                                                   }
{   THIS SOURCE CODE AND ALL RESULTING INTERMEDIATE FILES           }
{   ARE CONFIDENTIAL AND PROPRIETARY TRADE                          }
{   SECRETS OF DEVELOPER EXPRESS INC. THE REGISTERED DEVELOPER IS   }
{   LICENSED TO DISTRIBUTE THE PRODUCT AND ALL ACCOMPANYING .NET    }
{   CONTROLS AS PART OF AN EXECUTABLE PROGRAM ONLY.                 }
{                                                                   }
{   THE SOURCE CODE CONTAINED WITHIN THIS FILE AND ALL RELATED      }
{   FILES OR ANY PORTION OF ITS CONTENTS SHALL AT NO TIME BE        }
{   COPIED, TRANSFERRED, SOLD, DISTRIBUTED, OR OTHERWISE MADE       }
{   AVAILABLE TO OTHER INDIVIDUALS WITHOUT EXPRESS WRITTEN CONSENT  }
{   AND PERMISSION FROM DEVELOPER EXPRESS INC.                      }
{                                                                   }
{   CONSULT THE END USER LICENSE AGREEMENT FOR INFORMATION ON       }
{   ADDITIONAL RESTRICTIONS.                                        }
{                                                                   }
{*******************************************************************}
*/
#endregion Copyright (c) 2000-2008 Developer Express Inc.

using System.Collections.Generic;
using System.Diagnostics;
using System.Windows;
using System.Windows.Input;
using System.Threading;
using System.Windows.Controls;
using System.Windows.Media;
using System;
using System.Reflection;
using System.Windows.Browser;
using System.Globalization;
using System.Collections.ObjectModel;
using System.IO;
using System.Windows.Markup;
using System.Resources;
using System.Linq;
using System.Security;
using System.Text;
using System.Windows.Controls.Primitives;
using System.Windows.Threading;
namespace DevExpress.AgDataGrid {
	public static class AppHelper {
		public static void DebugOut(string str) {
			TextBlock tb = ((FrameworkElement)Application.Current.RootVisual).FindName("TimeTick") as TextBlock;
			tb.Text = str;
		}
	}
	public enum DefaultBoolean { Default = 0, False, True }
	public static class DefaultBooleanExtension {
		public static bool? ToBool(this DefaultBoolean db) {
			bool? res;
			if (db == DefaultBoolean.Default) res = null;
			else res = db == DefaultBoolean.True;
			return res;
		}
		public static bool IsDefault(this DefaultBoolean db) {
			return db == DefaultBoolean.Default;
		}
		public static bool Value(this DefaultBoolean db) {
			return db == DefaultBoolean.True;
		}
		public static bool HasValue(this DefaultBoolean db) {
			return db != DefaultBoolean.Default;
		}
	}
	internal static class DependencyPropertyExtension {
		private static Dictionary<DependencyObject, Dictionary<DependencyProperty, bool>> suspendedHandlers = new Dictionary<DependencyObject, Dictionary<DependencyProperty, bool>>();
		public static bool IsHandlerSuspended(this DependencyObject obj, DependencyProperty dependencyProperty) {
			if (suspendedHandlers.ContainsKey(obj)) {
				return suspendedHandlers[obj].ContainsKey(dependencyProperty);
			} else {
				return false;
			}
		}
		public static void SetValueNoCallback(this DependencyObject obj, DependencyProperty property, object value) {
			obj.SuspendHandler(property, true);
			try {
				obj.SetValue(property, value);
			} finally {
				obj.SuspendHandler(property, false);
			}
		}
		private static void SuspendHandler(this DependencyObject obj, DependencyProperty dependencyProperty, bool suspend) {
			if (suspendedHandlers.ContainsKey(obj)) {
				Dictionary<DependencyProperty, bool> suspensions = suspendedHandlers[obj];
				if (suspend) {
					suspensions[dependencyProperty] = true; 
				} else {
					suspensions.Remove(dependencyProperty);
				}
			} else {
				suspendedHandlers[obj] = new Dictionary<DependencyProperty, bool>();
				suspendedHandlers[obj][dependencyProperty] = true;
			}
		}
	}
	public delegate void MethodInvoker();
	internal static class UIElementExtension {
		static readonly Dictionary<UIElement, DispatcherTimer> ElementDictionary = new Dictionary<UIElement, DispatcherTimer>();
		public static readonly int ScrollTimerInterval = 100;
		public static Point GetPosition(this UIElement obj, UIElement relativeTo) {
			return obj.TransformToVisual(relativeTo).Transform(new Point());
		}
		public static bool IsVisible(this UIElement obj) {
			return obj.Visibility == Visibility.Visible;
		}
		public static void SetVisible(this UIElement obj, bool value) {
			obj.Visibility = value ? Visibility.Visible : Visibility.Collapsed;
		}
		public static void DelayedExecute(this UIElement scroll, MethodInvoker method) {
			if (ElementDictionary.ContainsKey(scroll)) {
				ElementDictionary[scroll].Stop();
				ElementDictionary[scroll] = CreateNewTimer(method);
			} else {
				ElementDictionary.Add(scroll, CreateNewTimer(method));
			}
		}
		static DispatcherTimer CreateNewTimer(MethodInvoker method) {
			DispatcherTimer timer = new DispatcherTimer();
			timer = new DispatcherTimer();
			timer.Interval = TimeSpan.FromMilliseconds(ScrollTimerInterval);
			timer.Tick += (d, e) => { method(); timer.Stop(); };
			timer.Start();
			return timer;
		}
	}
	internal interface IFrameworkElement {
		Size Measure(Size availableSize);
		void InvalidateMeasureEx();
	}
	internal static class FrameworkElementExtension {
		public static bool IsVisible(this FrameworkElement obj) {
			return ((UIElement)obj).IsVisible() && obj.Width != 0 && obj.Height != 0;
		}
		public static void InvalidateMeasureEx(this UIElement obj) {
			IFrameworkElement elem = obj as IFrameworkElement;
			if (elem == null) return;
#if DEBUGTEST
			Size res = elem.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
			((FrameworkElement)elem).Width = res.Width;
			((FrameworkElement)elem).Height = res.Height;
#else
			elem.InvalidateMeasureEx();
#endif
		}
		public static void MeasureEx(this UIElement obj, Size availableSize) {
#if DEBUGTEST
			IFrameworkElement elem = obj as IFrameworkElement;
			if (elem == null) {
				if (((FrameworkElement)obj).Parent != null)
					((FrameworkElement)obj).Measure(availableSize);
				return;
			}
			Size res = elem.Measure(availableSize);
			((FrameworkElement)elem).Width = res.Width;
			((FrameworkElement)elem).Height = res.Height;
#else
			obj.Measure(availableSize);
#endif
		}
		public static Size GetDesiredSize(this UIElement obj) {
			FrameworkElement elem = obj as FrameworkElement;
			if (elem == null) return new Size();
#if DEBUGTEST
			return new Size(elem.Width, elem.Height);
#else
			return elem.DesiredSize;
#endif
		}
	}
	internal static class KeyboardHelper {
		public static bool ShiftKey { get { return (Keyboard.Modifiers & ModifierKeys.Shift) > 0; } }
		public static bool CtrlKey { get { return (Keyboard.Modifiers & ModifierKeys.Control) > 0; } }
	}
	public delegate void MouseWheelEventHandler(object sender, MouseWheelHandlerEventArgs e);
	public class MouseWheelHandlerEventArgs : EventArgs {
		double delta;
		public MouseWheelHandlerEventArgs() : this(0) { }
		public MouseWheelHandlerEventArgs(double delta) {
			this.delta = delta;
		}
		public double Delta { get { return delta; } }
	}
	internal static class MouseHelper {
		static int Timeout = 500;
		static bool clicked = false;
		static Point position;
		public static bool IsDoubleClick(MouseButtonEventArgs e) {
			if (clicked) {
				clicked = false;
				return position.Equals(e.GetPosition(null));
			}
			clicked = true;
			position = e.GetPosition(null);
			ParameterizedThreadStart threadStart = new ParameterizedThreadStart(ResetThread);
			Thread thread = new Thread(threadStart);
			thread.Start();
			return false;
		}
		private static void ResetThread(object state) {
			Thread.Sleep(Timeout);
			clicked = false;
		}
		static List<MouseWheelEventHandler> wheelHandler = new List<MouseWheelEventHandler>();
		public static void SetMouseWheelHandler(MouseWheelEventHandler _wheelHandler) {
			wheelHandler.Add(_wheelHandler);
			if (HtmlPage.IsEnabled && HtmlPage.Window != null) {
				HtmlPage.Window.AttachEvent("DOMMouseScroll", OnMouseWheelTurned);
				HtmlPage.Window.AttachEvent("onmousewheel", OnMouseWheelTurned);
				HtmlPage.Document.AttachEvent("onmousewheel", OnMouseWheelTurned);
			}
		}
		static void OnMouseWheelTurned(Object sender, HtmlEventArgs args) {
			double delta = 0;
			ScriptObject eventObj = args.EventObject;
			if (eventObj.GetProperty("wheelDelta") != null) {  
				delta = ((double)eventObj.GetProperty("wheelDelta")) / 120;
				if (HtmlPage.Window.GetProperty("opera") != null)
					delta = -delta;
			} else if (eventObj.GetProperty("detail") != null) {
				delta = -((double)eventObj.GetProperty("detail")) / 3;
				if (HtmlPage.BrowserInformation.UserAgent.IndexOf("Macintosh") != -1)
					delta = delta * 3;
			}
			if (delta != 0) {
				args.PreventDefault();
				eventObj.SetProperty("returnValue", false);
			}
			foreach (MouseWheelEventHandler handler in wheelHandler) {
				handler(null, new MouseWheelHandlerEventArgs(delta));
			}
		}
	}
	public class AgDataGridDatePicker : DatePicker {
		const string TextBoxName = "TextBox";
		public AgDataGridDatePicker() {
			DefaultStyleKey = typeof(AgDataGridDatePicker);
			VerticalAlignment = VerticalAlignment.Center;
		}
		public TextBox TextEditor { get { return GetTemplateChild(TextBoxName) as TextBox; } }
		public override void OnApplyTemplate() {
			base.OnApplyTemplate();
			if (TextEditor != null) {
				TextEditor.Template = GridElementHelper.DatePickerTextBoxTemplate;
				TextEditor.Select(0, TextEditor.Text.Length);
			}
		}
	}
	public class AgDataGridTextBox : TextBox {
		public AgDataGridTextBox()
			: base() {
			DefaultStyleKey = typeof(AgDataGridTextBox);
			BorderThickness = new Thickness(0);
			Padding = new Thickness(0, 0, 0, 0);
			HorizontalAlignment = HorizontalAlignment.Left;
			Background = new SolidColorBrush(Colors.Transparent);
			Foreground = new SolidColorBrush(Colors.Black);
			Loaded += new RoutedEventHandler(AgDataGridTextBox_Loaded);
		}
		void AgDataGridTextBox_Loaded(object sender, RoutedEventArgs e) {
			int selectionLength = SelectionLength;
			SelectionLength = 0;
			UpdateLayout();
			SelectionLength = selectionLength;
		}
	}
	public class AgDataGridCheckBox : CheckBox {
		public AgDataGridCheckBox() : base() { }
	}
	public class AgStyle : ObservableCollection<AgSetter> {
	}
	public class AgSetter {
		public AgSetter() { }
		public String Property { get; set; }
		public object Value { get; set; }
	}
	public class StyleLoader {
		public static void ApplyStyle(DependencyObject obj, AgStyle style) {
			if (style == null) return;
			foreach (var baseSetter in style) {
				AgSetter setter = baseSetter as AgSetter;
				if (setter == null) continue;
				if (string.IsNullOrEmpty(setter.Property)) continue;
				PropertyInfo pi = obj.GetType().GetProperty(setter.Property);
				if (pi == null) continue;
				if (setter.Value is string) {
					object curValue = pi.GetValue(obj, null);
					if (curValue != null) {
						Type valueType = curValue.GetType();
						if (valueType.IsPrimitive) {
							pi.SetValue(obj, Convert.ChangeType((string)setter.Value, valueType, CultureInfo.InvariantCulture), null);
							continue;
						}
						if (valueType.IsEnum) {
							pi.SetValue(obj, Enum.Parse(valueType, (string)setter.Value, true), null);
							continue;
						}
					}
				}
				pi.SetValue(obj, setter.Value, null);
			}
		}
		public static void ApplyStyle(DependencyObject obj, Style style) {
			if (style == null) return;
			foreach (SetterBase baseSetter in style.Setters) {
				Setter setter = baseSetter as Setter;
				if (setter == null) continue;
				if (setter.Property == null) continue;
				if (setter.Value is string) {
					object curValue = obj.GetValue(setter.Property);
					if (curValue != null) {
						Type valueType = curValue.GetType();
						if (valueType.IsPrimitive) {
							obj.SetValue(setter.Property, Convert.ChangeType((string)setter.Value, valueType, CultureInfo.InvariantCulture));
							continue;
						}
						if (valueType.IsEnum) {
							obj.SetValue(setter.Property, Enum.Parse(valueType, (string)setter.Value, true));
							continue;
						}
					}
				}
				obj.SetValue(setter.Property, setter.Value);
			}
		}
	}
	public class FontLayoutHelper {
		string[] FontProp = { "FontFamily", "FontSize", "FontStretch", "FontStyle", "FontWeight", "Foreground" };
		Dictionary<string, object> FontValues = new Dictionary<string, object>();
		public FontLayoutHelper() { }
		public FontLayoutHelper(object cc) {
			Assign(cc);
		}
		public void SetFont(object tb) {
			if (tb == null) return;
			foreach (PropertyInfo pi in tb.GetType().GetProperties()) {
				if (FontValues.ContainsKey(pi.Name)) tb.GetType().GetProperty(pi.Name).SetValue(tb, FontValues[pi.Name], null);
			}
		}
		void Assign(object cc) {
			if (cc == null) return;
			foreach (PropertyInfo pi in cc.GetType().GetProperties()) {
				if (FontProp.Contains(pi.Name)) FontValues.Add(pi.Name, pi.GetValue(cc, null));
			}
		}
	}
	public class GridElementHelper {
		public static ControlTemplate DatePickerTextBoxTemplate { get; private set; }
		static GridElementHelper() {
			string xaml;
			if (!ResourceLoader.GetEmbeddedResource(typeof(GridElementHelper).Assembly, "themes/generic.xaml", out xaml))
				throw new Exception("generic.xaml was not found");
			xaml = xaml.Remove(0, xaml.IndexOf('<'));
			ResourceDictionary dictionary = XamlReader.Load(xaml) as ResourceDictionary;
			DatePickerTextBoxTemplate = dictionary["DatePickerTextBoxTemplate"] as ControlTemplate;
		}
	}
	public class ResourceLoader {
		public static bool GetEmbeddedResource(Stream stream, out string resource) {
			resource = "";
			StringBuilder s = new StringBuilder();
			if (stream == null) return false;
			try {
				int b;
				do {
					b = stream.ReadByte();
					if (b != -1)
						s.Append((Char)b);
				} while (b != -1);
			} finally {
				stream.Dispose();
			}
			resource = s.ToString();
			return true;
		}
		public static bool GetEmbeddedResource(Assembly assembly, string resourceName, out string resource) {
			resource = "";
			string[] manifestResourceNames = assembly.GetManifestResourceNames();
			string baseName = assembly.FullName;
			baseName = baseName.Substring(0, baseName.IndexOf(",")) + ".g";
			if (!manifestResourceNames.Contains(baseName + ".resources")) return false;
			StringBuilder s = new StringBuilder();
			ResourceManager manager = new ResourceManager(baseName, assembly);
			UnmanagedMemoryStream stream = manager.GetStream(resourceName);
			if (stream == null) return false;
			try {
				int b;
				do {
					b = stream.ReadByte();
					if (b != -1)
						s.Append((Char)b);
				} while (b != -1);
			} finally {
				stream.Dispose();
			}
			resource = s.ToString();
			return true;
		}
	}
}
